%{
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "symbol.c"
#include "gerador.c"
#include "offset.c"
#include "inicia.c"

int tipo_pog=0;
int yydebug=1;
extern int yylineno,yychar;
void yyerror(const char *str)
{
    printf("ERRO!!\nLinha: %d\n%s!\n",yylineno,str);
}
 
int yywrap()
{
    return 1;
} 
  
main()
{
    printf("******** Analisador Sintatico ********\n");
    YYSAIDA = fopen("saida.out","w");
    CODE = fopen("quadruplas.out","wb");
    INICIA();

    yyparse();
    fclose(CODE);
    CODE = fopen("quadruplas.out","rb");
    IMPRIMECODIGO();
    fclose(YYSAIDA);
	fclose(CODE);
} 


%}

%token PROGRAM BEGIN_ END DECLARE REAL ARRAY OF PROCEDURE IF THEN ELSE WHILE DO READ WRITE GOTO RETURN NOT OR MOD AND TRUE FALSE GE NE ASSIGN

%union{
    int number;
    char* string;
    struct{
        char* nome;
        int classe;
    }simbolo;
    struct{
        int inicio;
        int valor;
    }prochead
}

%token <number> CHARACTER
%token <string> ID
%token <number> INTEGER
%token <number> BOOLEAN
%token <number> CHAR
%token <number> LABEL
%token <number> NUMBER
%type <number> caractere 
%type <number> identifier
%type <number> simple_type 
%type <number> array_type 
%type <number> type
%type <number> tamanho
%type <number> integer_constant
%type <number> unsigned_integer
%type <number> variable
%type <number> array_element
%type <number> assign_stmt
%type <prochead> prochead

%right  '='
%left  '+'  '-' AND
%left  '*'  '/' OR MOD

%%
program           :
                  {toff = 0;
                   offset = 0;
                   proxq = 1;
                   GEN(CPROGBEGIN,0,0,0);                    
                  }
                  PROGRAM identifier block_stmt
                  {
                   GEN(CPROGEND,0,0,0);
                   SALVA(1,proxq-1);
                  }
                  ;

block_stmt        : BEGIN_ stmt_list END
                  | DECLARE decl_list BEGIN_ stmt_list END
                  ;

decl_list         : 
                  | decl 
                  | decl_list ';' decl
                  ;

decl              : 
                  | variable_decl
                  | proc_decl
                  ;

variable_decl     : type ident_list {tipo_pog = $1;}
                  ;

ident_list        : identifier
                  {
                    DECLARA($1,VARIAVEL,tipo_pog,offset);
                    offset++;
                  } 
                  | ident_list ',' identifier
                  {
                    DECLARA($3,VARIAVEL,tipo_pog,offset);
                    offset++;
                  } 
                  ;

type              : simple_type {$$=$1;}
                  | array_type {$$=$1;}
                  ;

simple_type       : INTEGER {$$=INTEIRO;} 
                  | BOOLEAN {$$=LOGICO;} 
                  | CHAR  {$$=CARACTERE;} 
                  | LABEL {$$=ROTULO;} 
                  ;

array_type        : ARRAY tamanho OF simple_type {$$ = $4;offset+=$2;}
                  ;

tamanho           : integer_constant {$$=$1;}
                  ;

proc_decl         : prochead block_stmt
                  {
                    TAMANHO($1.valor,offset);
                    POPOFF(offset);
                    ctx = 1;
                    GEN(CPROCEND,0,0,0);
                    FBLOCO();
                    SALVA($1.inicio,proxq-1);
                    proxq = $1.inicio;

                  };
                  | prochead '(' formal_list ')' block_stmt
                  {
                    TAMANHO($1.valor,offset);
                    POPOFF(offset);
                    ctx = 1;
                    GEN(CPROCEND,0,0,0);
                    FBLOCO();
                    SALVA($1.inicio,proxq-1);
                    proxq = $1.inicio;

                  };
                  ;

prochead          : PROCEDURE identifier
                  {
                    DECLARA($2,PROC,0,proxq);
                    $$.inicio = proxq;
                    $$.valor = $2;
                    GEN(CPROCBEGIN,$2,0,0);
                    ABLOCO();
                    PUSHOFF(offset);
                  };


formal_list       : parameter_decl 
                  | formal_list ';' parameter_decl
                  ;

parameter_decl    : parameter_type identifier
                  ;

parameter_type    : type
                  ;

proc_signature    : PROCEDURE identifier
                  | PROCEDURE identifier '(' type_list ')' 
                  ;

type_list         : parameter_type
                  | type_list ',' parameter_type
                  ;

stmt_list         : 
                  | stmt ';' 
                  | stmt_list ';' stmt
                  ;

stmt              : label ':' unlabelled_stmt 
                  | unlabelled_stmt
                  ;

label             : identifier
                  ;

unlabelled_stmt   : assign_stmt 
                  | if_stmt    
                  | while_stmt 
                  | read_stmt 
                  | write_stmt
                  | goto_stmt    
                  | proc_stmt 
                  | return_stmt 
                  | block_stmt
                  ;

assign_stmt       : variable ASSIGN expression
                  ;

variable          : identifier {$$=$1;}
                  | array_element {$$=$1;}
                  ;

array_element     : identifier '[' expression ']' {$$=$1;}
                  ;

if_stmt           : IF condition THEN stmt_list END
                  | IF condition THEN stmt_list ELSE stmt_list END
                  ;

condition         : expression
                  ;

while_stmt        : stmt_prefix stmt_list END
                  ;

stmt_prefix       : WHILE condition DO
                  ;

read_stmt         : READ '(' ident_list ')'
                  ;

write_stmt        : WRITE '(' expr_list ')'
                  ;

goto_stmt         : GOTO label
                  ;

proc_stmt         : identifier 
                  | identifier '(' expr_list ')' 
                  ;

return_stmt       : RETURN
                  ;

expr_list         : 
                  | expression 
                  | expr_list ',' expression
                  ;

expression        : simple_expr 
                  | simple_expr relop simple_expr
                  ;

simple_expr       : term 
                  | simple_expr addop term
                  ;

term              : factor_a 
                  | term mulop factor_a
                  ;

factor_a          : factor 
                  | NOT factor 
                  | '-' factor
                  ;

factor            : variable 
                  | constant 
                  | '(' expression ')'
                  ;

relop             : '=' 
                  | '>' 
                  | '<' 
                  | GE 
                  | NE 
                  ;

addop             : '+' 
                  | '-' 
                  | OR 
                  ;

mulop             : '*' 
                  | '/' 
                  | MOD 
                  | AND 
                  ;

constant          : integer_constant 
                  | char_constant 
                  | boolean_constant
                  ;

boolean_constant  : FALSE 
                  | TRUE
                  ;

integer_constant  : unsigned_integer {$$=$1;}
                  ;

unsigned_integer  : NUMBER {$$=$1;}
                  ;

char_constant     : caractere
                  ;

identifier        : ID
                  {
                      $$=PROCURAID($1);
                  }
                  ;

caractere         : CHARACTER 
                  {$$=$1;}
                  ;

%%


